package org.millioncall.yueyoga.admin.service.impl;

import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.millioncall.yueyoga.admin.dao.CheduleDetailsDAO;
import org.millioncall.yueyoga.admin.dao.ClazzDAO;
import org.millioncall.yueyoga.admin.dao.MemberDAO;
import org.millioncall.yueyoga.admin.dao.ProductDAO;
import org.millioncall.yueyoga.admin.dao.ReservationDAO;
import org.millioncall.yueyoga.admin.dao.WeiXinDAO;
import org.millioncall.yueyoga.admin.model.Clazz;
import org.millioncall.yueyoga.admin.model.Member;
import org.millioncall.yueyoga.admin.service.WeiXinService;
import org.millioncall.yueyoga.common.weixin.Article;
import org.millioncall.yueyoga.common.weixin.NewsMessage;
import org.springframework.stereotype.Service;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;

@Service
public class WeiXinServiceImpl implements WeiXinService {
	// 与接口配置信息中的Token要一致  
    private static String token = "qdyoga20141105";
    private static Map<String, String> status;
	private WeiXinDAO weiXinDAO;
	private MemberDAO memberDAO;
	private ProductDAO productDAO;
	private ClazzDAO clazzDAO;
	private CheduleDetailsDAO cheduleDetailsDAO;
	private ReservationDAO reservationDAO;
	public WeiXinDAO getWeiXinDAO() {
		return weiXinDAO;
	}

	public void setWeiXinDAO(WeiXinDAO weiXinDAO) {
		this.weiXinDAO = weiXinDAO;
	}

	public MemberDAO getMemberDAO() {
		return memberDAO;
	}

	public void setMemberDAO(MemberDAO memberDAO) {
		this.memberDAO = memberDAO;
	}

	public ClazzDAO getClazzDAO() {
		return clazzDAO;
	}

	public void setClazzDAO(ClazzDAO clazzDAO) {
		this.clazzDAO = clazzDAO;
	}

	public ReservationDAO getReservationDAO() {
		return reservationDAO;
	}

	public void setReservationDAO(ReservationDAO reservationDAO) {
		this.reservationDAO = reservationDAO;
	}

	public CheduleDetailsDAO getCheduleDetailsDAO() {
		return cheduleDetailsDAO;
	}

	public void setCheduleDetailsDAO(CheduleDetailsDAO cheduleDetailsDAO) {
		this.cheduleDetailsDAO = cheduleDetailsDAO;
	}

	public ProductDAO getProductDAO() {
		return productDAO;
	}

	public void setProductDAO(ProductDAO productDAO) {
		this.productDAO = productDAO;
	}

	@Override
	public String execute(String xmlData) {
		Map<String, String> msg = null;
		try {
			msg = parseXml(xmlData);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 保存到数据库
		weiXinDAO.saveWeiXinTable(msg);
		// 处理消息
		String handleMsg = handleMsg(msg);
		return handleMsg;
	}

	/** 判断信息TYPE **/
	@Override
	public String handleMsg(Map<String, String> msg) {
		String msgType = msg.get("MsgType");
		if ("event".equals(msgType)) {
			return handleEventMsg(msg);
		} else {
			return handleUnknowMsg(msg);
		}
	}

	/** 解析XML **/
	public Map<String, String> parseXml(String xmlData)
			throws DocumentException {
		Document doc = DocumentHelper.parseText(xmlData);
		Element rootElt = doc.getRootElement();
		@SuppressWarnings("unchecked")
		List<Element> list = rootElt.elements();

		HashMap<String, String> map = new HashMap<String, String>();
		for (Element e : list) {
			map.put(e.getName(), e.getText());
		}
		return map;
	}

	@Override
	public String handleUnknowMsg(Map<String, String> map) {
		return null;
	}

	@Override
	public String handleLinkMsg(Map<String, String> map) {
		return null;
	}

	//菜单事件绑定
	@Override
	public String handleEventMsg(Map<String, String> map) {
		String event = map.get("Event");
		String responseXml = "";
		if ("subscribe".equals(event)) {// 对于刚刚订阅用户的回复
			String content= "您好,欢迎关注青岛印想瑜伽会馆";
			responseXml=this.getTextReply(content,map);
		}else if("unsubscribe".equals(event)){
			List<Member> members=this.memberDAO.weixinFindMemberByProperty("openID", map.get("FromUserName"));
			for (Member member : members) {
				Map<String, Object> maps=new HashMap<String, Object>();
				maps.put("id",member.getMemberid());
				maps.put("openID", null);
				memberDAO.updateMemberOpenID(maps);
			}
		}else if("CLICK".equals(event)){
			String eventKey = map.get("EventKey");
			if("dingzuo".equals(eventKey)){
				responseXml=this.toFindClazzs(map);
			}else if("quxiaodingzuo".equals(eventKey)){
				responseXml=this.toCancelReservation(map);
			}else if("cardidbangding".equals(eventKey)){//使用卡号绑定
				map.put("bindingType", "cardid");
				responseXml=this.membersBinding(map);
			}else if("outidbangding".equals(eventKey)){//使用卡面码绑定
				map.put("bindingType", "outid");
				responseXml=this.membersBinding(map);
			}else if("mobilebangding".equals(eventKey)){//使用手机号绑定
				map.put("bindingType", "mobile");
				responseXml=this.membersBinding(map);
			}else if("clearbangding".equals(eventKey)){//解除绑定
				responseXml=this.clearMemberBinding(map);
			}
		}
		return responseXml;
	}
	
	//当微信端点击"取消订座"时，查询该用户的定座记录
	private String toCancelReservation(Map<String, String> map) {
		String content= "";
		List<Member> members=this.memberDAO.weixinFindMemberByProperty("openID", map.get("FromUserName"));
		if(members.size()>0){
			Map<String, Object> maps=new HashMap<String, Object>();
			maps.put("memberId",members.get(0).getMemberid());
			if(this.cheduleDetailsDAO.deleteAllCheduleByMap(maps)){
				content="取消订座成功！";
			}else{
				content="您现在没有可用的订座记录";
			}
		}else{
			content="您的微信号还没有与会馆会员进行绑定,请先进行绑定";
		}
		return getTextReply(content,map);
	}
	//查询该用户选择消费的产品的可选班级
	private String toFindClazzs(Map<String, String> map) {
		String responseXml="";
		List<Member> members=this.memberDAO.weixinFindMemberByProperty("openID", map.get("FromUserName"));
		if(members.size()>0){
			Map<String, Object> maps=new HashMap<String, Object>();
			maps.put("id", members.get(0).getMemberid());
			maps.put("time", new Date());
			List<Clazz> clazzs=this.clazzDAO.findWeiXinClassByMap(maps);
			if(clazzs.size() >0){
				NewsMessage newsMessage = new NewsMessage();
				newsMessage.setToUserName(map.get("FromUserName"));
				newsMessage.setFromUserName(map.get("ToUserName"));
				newsMessage.setCreateTime(new Date().getTime());
				newsMessage.setMsgType("news");
				newsMessage.setFuncFlag(0);
				List<Article> articleList = new ArrayList<Article>();
				Article article = new Article();
				article.setTitle("您所在班级:");
				articleList.add(article);
				for (int i = 0; i < clazzs.size(); i++) {
					Article article1 = new Article();
					article1.setTitle((i+1)+".  "+clazzs.get(i).getName());
					article1.setUrl(map.get("basePath")+"weixin/scheduleListByDate.jhtml?memberId="+maps.get("id")+"&clazzId="+clazzs.get(i).getId());
					articleList.add(article1);
				}
				// 设置图文消息个数
				newsMessage.setArticleCount(articleList.size());
				// 设置图文消息包含的图文集合
				newsMessage.setArticles(articleList);
				// 将图文消息对象转换成xml字符串
				responseXml=newsMessageToXml(newsMessage);
			}else{
				responseXml=this.getTextReply("您现在还没有课程安排", map);
			}
		}else{
			responseXml=this.getTextReply("您的微信号还没有与会馆会员进行绑定,请先进行绑定", map);
		}
		return responseXml;
	}

	//当微信端点击"会员绑定"时，查询该用户的是否绑定
	private String membersBinding(Map<String, String> map) {
		String content= "";
		List<Member> members=this.memberDAO.weixinFindMemberByProperty("openID", map.get("FromUserName"));
		if(members.size()>0){
			content="您的微信号已经与会员进行绑定";
		}else{
			
			if(status==null){
				status=new HashMap<String, String>();
			}
			status.put(map.get("FromUserName"), "绑定账户");
			
			String type = map.get("bindingType");
			status.put("bindingType", type);
			
			if("cardid".equals(type)){
				content="请输入您要绑定的会员卡号";
			}else if("outid".equals(type)){
				content="请输入您要绑定的会员卡面码";
			}else if("mobile".equals(type)){
				content="请输入您要绑定的会员手机号";
			}
			
		}
		return getTextReply(content,map);
	}
	
	//当微信端点击"会员解除绑定"时
	private String clearMemberBinding(Map<String,String> map) {
		String content= "";
		List<Member> members=this.memberDAO.weixinFindMemberByProperty("openID", map.get("FromUserName"));
		if(members.size()>0){//已经绑定，开始解除
			for(Member m:members){
				m.setOpenID("");
				this.memberDAO.update(m);
			}
			content="您的微信号已解除与会员绑定";
		}else{
			content="您的微信号尚未与会员进行绑定";
		}
		return getTextReply(content,map);
	}

	@Override
	public String getTextReply(String content, Map<String, String> map) {
		Map<String, String> reply = new HashMap<String, String>();
		
		System.out.println("wechat:"+content);
		
		
		reply.put("Content", content);
		reply.put("ToUserName", map.get("FromUserName"));
		reply.put("FromUserName", map.get("ToUserName"));
		reply.put("CreateTime", new Date().getTime() + "");
		reply.put("MsgType", "text");
		reply.put("FuncFlag", "0");
		return generatorXml(reply);
	}
	
	public String getNewsReply(List<String> content, Map<String, String> map) {
		Map<String, String> reply = new HashMap<String, String>();
		reply.put("ToUserName", map.get("FromUserName"));
		reply.put("FromUserName", map.get("ToUserName"));
		reply.put("CreateTime", new Date().getTime() + "");
		reply.put("MsgType", "news");
		reply.put("ArticleCount", content.size()+"");
		Document document = DocumentHelper.createDocument();
		document.setXMLEncoding("UTF-8");
		Element root = document.addElement("xml");
		for (Entry<String, String> entry : reply.entrySet()) {
			Element e = root.addElement(entry.getKey());
			e.setText(entry.getValue());
		}
		Element article = root.addElement("Articles");
		for (int i = 0; i < content.size(); i++) {
			Element item = article.addElement("item");
			Element title = item.addElement("Title");
			title.setText(content.get(i));
		}
		String xml = document.getRootElement().asXML();
		return xml;
	}

	@Override
	public String generatorXml(Map<String, String> reply) {
		if (null == reply) {
			return null;
		}
		Document document = DocumentHelper.createDocument();
		document.setXMLEncoding("UTF-8");
		Element root = document.addElement("xml");
		for (Entry<String, String> entry : reply.entrySet()) {
			Element e = root.addElement(entry.getKey());
			e.setText(entry.getValue());
		}
		String xml = document.getRootElement().asXML();
		return xml;
	}

	@Override
	public String handleImageMsg(Map<String, String> map) {
		Map<String, String> reply = new HashMap<String, String>();
		reply.put("Content", "Image");
		reply.put("ToUserName", map.get("FromUserName"));
		reply.put("FromUserName", map.get("ToUserName"));
		reply.put("CreateTime", new Date().getTime() + "");
		reply.put("MsgType", "image");
		reply.put("FuncFlag", "0");
		return generatorXml(reply);
	}

	@Override
	public String handleLocationMsg(Map<String, String> map) {
		Map<String, String> reply = new HashMap<String, String>();
		reply.put("Content", "Link");
		reply.put("ToUserName", map.get("FromUserName"));
		reply.put("FromUserName", map.get("ToUserName"));
		reply.put("CreateTime", new Date().getTime() + "");
		reply.put("MsgType", "text");
		reply.put("FuncFlag", "0");
		return generatorXml(reply);
	}

	@Override
	public String handleTextMsg(Map<String, String> map) {
		String responseXml = "";
		if(status!=null&&status.get(map.get("FromUserName"))!=null){
			if(status.get(map.get("FromUserName")).equals("绑定账户")){
				Map<String, Object> maps=new HashMap<String, Object>();
				
				String type = status.get("bindingType");
				if("cardid".equals(type)){
					maps.put("columnName", "cardNumber");
				}else if("outid".equals(type)){
					maps.put("columnName", "outside_card_no");
				}else if("mobile".equals(type)){
					maps.put("columnName", "phone");
				}
				
				maps.put("value", map.get("Content"));
				
				Member member=this.memberDAO.weixinFindByCardNumber(maps);
				if(member==null){
					responseXml=this.getTextReply("您要绑定的会员不存在", map);
				}else{
					member.setOpenID(map.get("FromUserName"));
					if(this.memberDAO.update(member)>0){
						responseXml=this.getTextReply("会员绑定成功", map);
						status.remove(map.get("FromUserName"));
					}else{
						responseXml=this.getTextReply("会员绑定失败,请使用“一键咨询”联系会馆或稍后再试", map);
					}
				}
			}
		}
		return responseXml;
	}

	@Override
	public boolean check(String signature, String timestamp, String nonce) {
		return weiXinDAO.check(signature, timestamp, nonce,token);
	}
	
	/**
	 * 图文消息对象转换成xml
	 * 
	 * @param newsMessage
	 *            图文消息对象
	 * @return xml
	 */
	public static String newsMessageToXml(NewsMessage newsMessage) {
		xstream.alias("xml", newsMessage.getClass());
		xstream.alias("item", new Article().getClass());
		return xstream.toXML(newsMessage);
	}

	/**
	 * 扩展xstream，使其支持CDATA块
	 * 
	 * @date 2014-10-8
	 */
	private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				// 对所有xml节点的转换都增加CDATA标记
				boolean cdata = true;
				@SuppressWarnings("unchecked")
				public void startNode(String name, Class clazz) {
					super.startNode(name, clazz);
				}

				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						writer.write("<![CDATA[");
						writer.write(text);
						writer.write("]]>");
					} else {
						writer.write(text);
					}
				}
			};
		}
	});

}
